#include <cstdlib>  //abs
#include <algorithm>    //std::count

#include "mission.h"
#include "game.h"

using namespace std;

Mission::Mission(Player* p, Game* g, const int& id) : playerChar(p), game(g), ID(id)
{
    //null;
}

Mission::~Mission()
{
    //null;
}

void Mission::readText(const int& n, ifstream& infile)
{
    // fills up the text from a filestream
    text = "";
    getline(infile, text);
    for (int i = 1; i < n; ++i)
    {
        string str;
        getline(infile, str);
        text = text + "\n" + str;
    }
}

void Mission::setNexts(const int& i1, const int& i2)
{
    // sets which missions will be the next
    next1 = i1;
    next2 = i2;
}

void Mission::save(std::ostream& outfile) const
{
    // saves the missions data to a filestream
    outfile << getID() << " " << getPuzzle() << " "
        << std::count(text.begin(), text.end(), '\n') + 1 << '\n'
        << getText() << '\n' << next1 << " " << next2 << " ";
}

void Mission::completeMission()
{
    // finishes the mission
    playerChar->gainExperience(getExperience());
    // nextmission offers
    if (next2 == 0)
    {
        if (next1 == 0)
        {
            cout << "Congratulations, you completed all missions, you won!" << endl;
        } else
        {
            game->nextMission(next1);
        }
    } else
    {
        cout << "Which path do you want to take? The one to the left (L) or the one to the right (R)?\t";
        char c;
        cin >> c;
        while (cin.fail() || (c != 'l' && c != 'L' && c != 'r' && c != 'R'))
        {
            cout << endl << "invalid answer, please try again\t";
            cin.clear(); while (cin.peek() != '\n') cin.ignore();
            cin >> c;
        }
        cin.clear(); while (cin.peek() != '\n') cin.ignore();
        if (c == 'l' || c == 'L')
        {
            game->nextMission(next1);
        } else if (c == 'r' || c == 'R')
        {
            game->nextMission(next2);
        }
    }
}

void Mission::failMission()
{
    //cout << "You lost the game!" << endl;
    game->quitGame();
}

//----------------------------

Puzzle::Puzzle(Player* p, Game* g, const int& id) : Mission(p,g,id)
{
    //null;
}

void Puzzle::setData(const int& ans, const int& marg, const int& exp)
{
    answer = ans;
    errorMargin = marg;
    experience = exp;
}

void Puzzle::answerTry(const int& ans)
{
    // attempts to solve the puzzle with a given number,
    if (ans == answer)
    {
        cout << "That's correct! You gain "<< getExperience() << " experience points!" << endl;
        completeMission();
    } else if (abs(ans - answer) <= errorMargin && getExperience() > 0)
    {
        cout << "The correct answer is " << answer << ", but this is close, you gain " << getExperience() - 1 << " experience points!" << endl;
        --experience;
        completeMission();
    } else
    {
        cout << "Incorrect asnwer. ";
        if (getExperience() > 0)
        {
            cout << "Try again (tries left:" << getExperience() << "):\t";
            --experience;
            int x;
            cin >> x;
            while (cin.fail())
            {
                cin.clear(); while (cin.peek() != '\n') cin.ignore();
                cout << endl << "That's not a number, try again:\t";
                cin >> x;
            }
            cin.clear(); while (cin.peek() != '\n') cin.ignore();
            answerTry(x);
        } else
        {
            cout << "You have no tries left! The correct answer would be " << answer << "." << endl;
            failMission();
        }
    }
}

void Puzzle::save(std::ostream& outfile) const
{
    // saves the missions data to a filestream
    Mission::save(outfile);
    outfile << answer << " " << errorMargin << " " << experience << endl;
}

//---------------------

Combat::Combat(Player* p, Game* g, const int& id) : Mission(p,g,id), enemy(NULL), autoc(false)
{
    //null;
}

Combat::~Combat()
{
    if (enemy) delete enemy;
}

void Combat::setMonster(const std::string& name, const int& hp, const int& atk, const int& def, const int& spd, const int& exp)
{
    enemy = new Monster(name, playerChar, hp, atk, def, spd, exp);
}

void Combat::startCombat()
{
    // the first round of combat
    enemy->startCombat();
    playerChar->startCombat();
    playerChar->setEnemy(enemy);

    cout << "Do you want automatic combat? (y / n)\t";

    char c;
    cin >> c;

    while (cin.fail() || (c != 'y' && c != 'Y' && c != 'n' && c != 'N'))
    {
        cin.clear(); while (cin.peek() != '\n') cin.ignore();
        cout << endl << "invalid answer, please try again\t";
        cin >> c;
    }
    cin.clear(); while (cin.peek() != '\n') cin.ignore();
    autoc = (c == 'y' || c == 'Y');

    nextTurn();
}

void Combat::speedCheck()
{
    // one round of combat
    enemy->writeStats();
    playerChar->writeStats();
    if (playerChar->getCurrentSpeed() < enemy->getCurrentSpeed())
    {
        enemy->attack();
        enemy->setCurrentSpeed(enemy->getCurrentSpeed() - playerChar->getCurrentSpeed());
        playerChar->setCurrentSpeed(playerChar->getSpeed());
    } else
    {
        playerChar->tick();
        // PLAYERTURN
        if (autoc)
        {
            playerChar->useSkill(1);
        } else
        {
            for (int i = 1; i < 5; ++i)
            {
                if (playerChar->getCooldown(i) == 0)
                {
                    cout << i << " to use " << playerChar->getSkillName(i) << endl;
                } else
                {
                    cout << playerChar->getSkillName(i) << " has " << playerChar->getCooldown(i) << " turns cooldown time left" << endl;
                }
            }
            int x;
            cin >> x;
            while (cin.fail() || x < 1 || x > 4 || playerChar->getCooldown(x) > 0)
            {
                cout << "invalid ability number, try again" << endl;
                cin.clear(); while (cin.peek() != '\n') cin.ignore();
                cin >> x;
            }
            cin.clear(); while (cin.peek() != '\n') cin.ignore();
            playerChar->useSkill(x);
            cout << endl;
        }
        playerChar->setCurrentSpeed( playerChar->getCurrentSpeed() - enemy->getCurrentSpeed());
        enemy->setCurrentSpeed(enemy->getSpeed());
    }
    nextTurn();
}

void Combat::nextTurn()
{
    // checks for end of combat, starts a turn if it hasn't ended yet
    if (playerChar->isDead())
    {
        cout << "You have been defeated in combat by " << enemy->getName() << "." << endl;
        failMission();
    } else if (enemy->isDead())
    {
        cout << "You have defeated " << enemy->getName() << ", you gain " << getExperience() << " experience points!" << endl;
        completeMission();
    } else
    {
        speedCheck();
    }
}

void Combat::save(std::ostream& outfile) const
{
    // saves the missions data to a filestream
    Mission::save(outfile);
    outfile << enemy->getName() << " " << enemy->getMaxHealth() << " "
        << enemy->getAttack() << " " << enemy->getDefense() << " "
        << enemy->getSpeed() << " " << enemy->getExperience() << endl;
}

int Combat::getExperience() const
{
    return enemy->getExperience();
}
